Shader "Examples/05 Phong Bump"
{
    Properties
    {
        _BaseColor("Color", Color) = (1, 1, 1, 1)
        _BaseMap("Base Map", 2D) = "white" {}
        _BumpMap("Normal Map", 2D) = "bump" {}
        _BumpScale("Bump Scale", Float) = 1.0
        
        _SpecularColor("Specular Color", Color) = (1, 1, 1, 1)
        [PowerSlider(5.0)] _Shininess ("Shininess", Range (0.03, 1)) = 0.078125
        
        [KeywordEnum(Lambert,HalfLambert)] LAMBERT_TYPE("Lambert Type", Float) = 0
        [KeywordEnum (Phong,Blinn)] SPECULAR_TYPE("Specular Type", Float) = 0
    }
    SubShader
    {
        Tags 
        {
            "RenderPipeline" = "UniversalPipeline"
            "LightMode" = "UniversalForward"
            "Queue" = "Geometry"
        }

        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

        #pragma multi_compile LAMBERT_TYPE_LAMBERT  LAMBERT_TYPE_HALFLAMBERT
        #pragma multi_compile SPECULAR_TYPE_BLINN SPECULAR_TYPE_PHONG

        TEXTURE2D(_BaseMap);    SAMPLER(sampler_BaseMap);
        TEXTURE2D(_BumpMap);    SAMPLER(sampler_BumpMap);

        CBUFFER_START(UnityPerMaterial)
            half4 _BaseMap_ST;
            half4 _BaseColor;
            half4 _SpecularColor;
            half _Shininess;
        
            half _BumpScale;
        CBUFFER_END
        
        ENDHLSL

        pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct a2v
            {
                float4 positionOS   : POSITION;
                float3 normalOS     : NORMAL;
                float4 tangentOS    : TANGENT;
                float2 texcoord     : TEXCOORD;
            };

            struct v2f
            {
                float4 positionCS   : SV_POSITION;
                float3 positionWS   : TEXCOORD0;
                float3 normalWS     : NORMAL;
                float3 tangentWS    : TANGENT;
                float3 bitangentWS  : TEXCOORD1;
                float2 uv           : TEXCOORD2;
            };

            v2f vert(a2v input)
            {
                v2f output;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                output.positionCS = vertexInput.positionCS;
                output.positionWS = vertexInput.positionWS;
                
                VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
                output.normalWS = normalInput.normalWS;
                output.tangentWS = normalInput.tangentWS;
                output.bitangentWS = normalInput.bitangentWS;

                output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
                return output;
            }

            half4 frag(v2f input):SV_Target
            {
                Light light = GetMainLight();
                half3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv), _BumpScale);
                half3 normalWS = TransformTangentToWorld(normalTS, half3x3(input.tangentWS, input.bitangentWS, input.normalWS));
                half3 viewDir = normalize(GetCameraPositionWS() - input.positionWS);
                half3 ambient = SampleSH(normalWS);
                
                half3 fianlCol = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).rgb * _BaseColor.rgb;
                #ifdef LAMBERT_TYPE_LAMBERT
                    half diffuse = saturate(dot(normalWS, light.direction));
                #else
                    half diffuse = saturate(dot(normalWS, light.direction) * 0.5h + 0.5h);
                #endif
                
                #ifdef SPECULAR_TYPE_BLINN
                    half3 halfDir = normalize(light.direction + viewDir);
                    half specular = pow(saturate(dot(normalWS, halfDir)), _Shininess * 128);
                #else
                    half3 reflectDir = normalize(reflect(-light.direction, normalWS));
                    half specular = pow(saturate(dot(viewDir, reflectDir)),  _Shininess * 128);
                #endif
                
                fianlCol.rgb *= diffuse * light.color + ambient;
                fianlCol.rgb += _SpecularColor.rgb * _SpecularColor.a * light.color * specular;
                
                return half4(fianlCol.rgb, 1);
            }
            ENDHLSL
        }
    }
}
